#ifndef _LINUX_PCIE_DMA_H
#define _LINUX_PCIE_DMA_H

#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/types.h>

#define DMA_DEFAULT_SIZE                (256 * 1024)    /* 256KB */
#define DMA_PACKET_LEN_MAX              (1024 * 4)      /* 数据包长度最大值，位宽 10bit，单位 DW，共 2^10 * 4 = 4096byte */
#define DMA_FRAME_SIZE                  (64*1024)       /* 64KB */

#define DMA_CPU_PHYS_ADDR_LOW_REG       0x200           /* 存储 CPU 内存低 32 位地址寄存器 */
#define DMA_CPU_PHYS_ADDR_HIGH_REG      0x204           /* 存储 CPU 内存高 32 位地址寄存器 */
#define DMA_FPGA_RAM_ADDR_REG           0x210           /* CplD 数据在 RAM 的初始地址寄存器 */
#define DMA_FPGA_RAM_LEN_REG            0x220           /* CplD 数据在 RAM 的数据包长度寄存器(单位DW) */
#define DMA_FPGA_STATUS_REG             0x230           /* 状态寄存器 */
#define DMA_FPGA_DATA_TYPE_REG          0x240           /* 数据类型寄存器 */

#define DMA_WAIT_DATA_CPL_CNT           100             /* 等待数据操作完成，读取状态寄存器次数 */

struct pcie_dma_t {
    void *parent;                       /* 父设备指针 */
    struct device *dev;                 /* 设备描述符 */
    void __iomem *reg_base;             /* 寄存器空间映射（内核虚拟地址） */
    dma_addr_t alloc_phys;              /* DMA 申请的内存物理地址（给FPGA用） */
    void *alloc_virt;                   /* DMA 申请的内存虚拟地址（内核用） */
    size_t pl_size;                     /* DMA 内存大小（默认256KB） */
    dma_addr_t ps_addr;                 /* DMA 设置的内存物理地址（给FPGA用） */
    /* DMA数据包最大4KB */
    u32 pkt_addr;                       /* DMA 设置的 FPGA 数据包源地址 */
    u32 pkt_len;                        /* DMA 设置的 FPGA 数据包长度（默认4KB>>2-1） */
    u32 pkt_size;                       /* DMA 设置的 FPGA 数据包大小（默认4KB） */
    u8 addr_type;                       /* CPU 设置的 地址长度，0 - 32位地址，1 - 64位地址 */
    u32 pkt_cnt;                        /* DMA 数据包计数 */
    /* DMA多包数据组成一帧数据 */
    u32 frame_size;                     /* DMA 帧大小 */
    u32 frame_cnt;                      /* DMA 帧计数 */
    bool frame_done;                    /* DMA 帧完成标志（1:完成，0:未完成） */
    wait_queue_head_t wq_frame;         /* 等待队列（等待帧完成） */
    /* DMA内存组成环形缓冲区 */
    spinlock_t frame_lock;              /* 缓冲区自旋锁 */
    u32 frame_head;                     /* DMA 帧头，记录写入位置 */
    u32 frame_tail;                     /* DMA 帧尾，记录读取位置 */
};

int init_pcie_dma(void *parent, struct device *dev, 
                  struct pcie_dma_t *dma, void __iomem *reg_base);      /* 初始化 PCIe DMA */
int start_pcie_dma(struct pcie_dma_t *dma);                             /* 开始 PCIe DMA 传输 */
int update_pcie_dma_addr(struct pcie_dma_t *dma);                       /* 更新 PCIe DMA 地址 */

#endif /*_LINUX_PCIE_DMA_H */
